#include "tcp_server.h"

TcpSerVer::TcpSerVer(/* args */)
{
    m_server_fd_ = -1;
    m_start_process_flag_ = false;
}

TcpSerVer::~TcpSerVer()
{
    Stop();
}

bool TcpSerVer::Init(std::string ip, int32_t port)
{
    m_ip_ = ip;
    m_port_ = port;

    m_server_sockaddr_.sin_family = AF_INET;
    m_server_sockaddr_.sin_port = htons(port);
    m_server_sockaddr_.sin_addr.s_addr = inet_addr(ip.c_str());

    m_server_fd_ = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC,IPPROTO_TCP);

    if(m_server_fd_ < 0){
        printf("tcp server fd init fail!!!\n");
        return false;
    }

    int socketoptvalue = 1;
    setsockopt(m_server_fd_, SOL_SOCKET,SO_REUSEADDR, (const char*)&socketoptvalue, sizeof(int));

        //SO_RCVBUF              发送缓冲区
    socketoptvalue = 128 * 1024;
    setsockopt(m_server_fd_, SOL_SOCKET, SO_RCVBUF, (const char*)(&socketoptvalue), sizeof(int));
    setsockopt(m_server_fd_, SOL_SOCKET, SO_SNDBUF, (const char*)&socketoptvalue, sizeof(int));

    socketoptvalue = 3;
    setsockopt(m_server_fd_, SOL_SOCKET, SO_RCVTIMEO, (const char*)(&socketoptvalue), sizeof(int));
    setsockopt(m_server_fd_, SOL_SOCKET, SO_SNDTIMEO, (const char*)(&socketoptvalue), sizeof(int));

    if(bind(m_server_fd_, (struct sockaddr*)&m_server_sockaddr_, sizeof(struct sockaddr)) < 0){
        printf("tcp bind fail!!!\n");
        return false;
    }

    if(listen(m_server_fd_, 10) < 0){
        printf("listen error!!!\n");
        return false;
    }

    
    return true;
}

bool TcpSerVer::Start()
{
    printf("%s\n", __FUNCTION__);
    m_start_process_flag_ = true;
    process_thread_.reset(new std::thread([&] (){
        Listen();
        while (m_start_process_flag_)
        {
            /* code */
            if(!ProcessLoop()){
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
                
        }

        printf("process thread end!\n");
        
    }));

    send_thread_.reset(new std::thread([&] (){
        while (m_start_process_flag_)
        {
            /* code */
            //  tmp;
            tx_buf_mutex_.lock();
            if(send_data_buf_.empty()){
                tx_buf_mutex_.unlock();
                // printf("wait client connect!\n");
                std::this_thread::sleep_for(std::chrono::milliseconds(1000));
                continue;
            }
            DataPacket& tmp = send_data_buf_.front();
            send_data_buf_.pop_front();
            tx_buf_mutex_.unlock();
            // printf("send data:%02x%02x\n",tmp.data[0],tmp.data[1]);

            int v = write(tmp.dst, (char*)tmp.data, (size_t)tmp.len);
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }

        printf("send thread end!\n");
        
    }));
    return true;
}

bool TcpSerVer::Stop()
{
    m_start_process_flag_ = false;
    if(send_thread_&&send_thread_->joinable()){
        send_thread_->join();
    }
    send_data_buf_.clear();

    if(process_thread_&&process_thread_->joinable()){
        process_thread_->join();
    }

    for(auto iter = m_client_vec_.begin(); iter != m_client_vec_.end(); ++iter)
    {
        close(iter->first);
    }
    m_client_vec_.clear();

    if(m_server_fd_ > 0)
        close(m_server_fd_);

    return true;
}

bool TcpSerVer::SendData(const uint8_t *data, int32_t len, int fd)
{
    if(m_client_vec_.size() <= 0)
        return false;
    int32_t size = send_data_buf_.size();
    DataPacket tmp;
    tmp.data = data;
    tmp.len = len;
    tmp.dst = fd;
    tx_buf_mutex_.lock();
    send_data_buf_.emplace_back(tmp);
    tx_buf_mutex_.unlock();

    // if(size == 0){
    //     uint64_t u = 1;
    //     ssize_t v = write(m_event_socket_, &u, sizeof(uint64_t));
    //     if (v < 0)
    //         return false;
    // }

    return true;
}

void TcpSerVer::Listen()
{ 
    unsigned long ul = 1;
    ioctl(m_server_fd_, FIONBIO, &ul);  //设置为非阻塞模式
    int addr_len = sizeof(struct sockaddr_in);
    int client_fd;
    sockaddr_in remote_addr;
    while (m_start_process_flag_) {
        client_fd = accept(m_server_fd_, (struct sockaddr*)&remote_addr, (socklen_t*)&addr_len);
        if (client_fd < 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            continue;
        }
        m_client_fd_ = client_fd;
        m_client_vec_.insert(std::make_pair(client_fd,remote_addr));
        printf("first client [port:%d] ip is %s\n", ntohs(remote_addr.sin_port), inet_ntoa(remote_addr.sin_addr));
        break;
    }
}

bool TcpSerVer::ProcessLoop()
{

    fd_set rfds;
    int32_t maxfd = 0;

    FD_ZERO(&rfds);

    if(maxfd < m_server_fd_)
        maxfd = m_server_fd_;
    
    FD_SET(m_server_fd_, &rfds);
    for(auto iter = m_delete_vec_.begin(); iter != m_delete_vec_.end(); ++iter){
        if(m_client_vec_.find(*iter)!= m_client_vec_.end()){
            m_client_vec_.erase(*iter);
        }
    }
    m_delete_vec_.clear();
    

    for(auto iter = m_client_vec_.begin(); iter != m_client_vec_.end(); ++iter){
        if(iter->first != -1){
            FD_SET(iter->first, &rfds);
            if(iter->first > maxfd)
                maxfd = iter->first;
        }
    }


    struct timeval tv = { 0, 500 * 1000 };
    int ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
    uint8_t tmpBuf[1024];
    if(ret > 0){
        if(FD_ISSET(m_server_fd_, &rfds)){
            int addr_len = sizeof(struct sockaddr_in);
            int client_fd;
            sockaddr_in remote_addr;
            unsigned long ul = 1;
            ioctl(m_server_fd_, FIONBIO, &ul);  //设置为非阻塞模式
            client_fd = accept(m_server_fd_, (struct sockaddr*)&remote_addr, (socklen_t*)&addr_len);
            if (-1 != client_fd) {
                // m_client_fd_ = client_fd;
                m_client_vec_.insert(std::make_pair(client_fd,remote_addr));
                printf("client[%ld][port:%d] ip is %s\n", m_client_vec_.size()-1, ntohs(remote_addr.sin_port), inet_ntoa(remote_addr.sin_addr));
            }
        }

        //read client
        for(auto iter = m_client_vec_.begin(); iter != m_client_vec_.end(); iter++){
            if(FD_ISSET(iter->first, &rfds)){
            //read client 
                char buffer[1024];   
                memset(buffer, 0 ,sizeof(buffer));
                int len = recv(iter->first, buffer, sizeof(buffer), 0);
                if(len <= 0){
                    close(iter->first);
                    m_delete_vec_.push_back(iter->first);
                    continue;
                }
                DataPacket tmp;
                tmp.data = (const uint8_t*)buffer;
                tmp.len = len;
                tmp.src = iter->first;

                //callback
                printf("recv:%s\n",buffer);
                if(m_rx_callback_){
                    m_rx_callback_(m_rx_callback_param_,tmp);
                }
            }
        }
    }

    return ret >= 0;

}